package com.mi.system.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mi.common.core.util.TreeUtils;
import com.mi.system.dto.query.DeptQueryDTO;
import com.mi.system.dto.request.DeptRequestDTO;
import com.mi.system.entity.Dept;
import com.mi.system.entity.User;
import com.mi.system.mapper.DeptMapper;
import com.mi.system.vo.DeptTreeVO;
import com.mi.system.vo.DeptVO;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Objects;

/**
 * Dept service
 *
 * @author jin_huaquan
 * @version 1.0
 * @date 2021/11/1 13:58
 */
@CacheConfig(cacheNames = "dept")
@Service
@RequiredArgsConstructor
public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements DeptService {

    private final UserService userService;

    @Override
    public IPage<DeptVO> listDept(Page page, DeptQueryDTO query) {
        return baseMapper.selectByPage(page, query);
    }

    @Override
    public List<DeptVO> listDept(DeptQueryDTO query) {
        return baseMapper.selectByQuery(query);
    }

    @Override
    public List<DeptTreeVO> listDeptTree(Long parentId) {
        if (Objects.isNull(parentId)) {
            parentId = 0L;
        }
        List<DeptTreeVO> depts = baseMapper.selectByParentId(parentId);

        return TreeUtils.build(depts, parentId.toString());
    }

    @Override
    @Transactional(rollbackFor = TransactionException.class)
    public boolean saveDept(DeptRequestDTO request) {
        Assert.isFalse(existsByParentIdAndName(request.getParentId(), request.getName()), "同一层级下已存在相同名称的部门");

        Dept dept = new Dept();

        BeanUtil.copyProperties(request, dept);

        return this.save(dept);
    }

    @Override
    @Transactional(rollbackFor = TransactionException.class)
    public boolean updateDept(Long id, DeptRequestDTO request) {
        Dept dept = baseMapper.selectById(id);
        Assert.notNull(dept, "未找到对应的部门");

        BeanUtil.copyProperties(request, dept);

        return this.updateById(dept);
    }

    @Override
    @Transactional(rollbackFor = TransactionException.class)
    public Dept removeDept(Long id) {
        Dept dept = baseMapper.selectById(id);
        Assert.notNull(dept, "未找到对应的部门");

        long count = userService.count(Wrappers.<User>lambdaQuery().eq(User::getDeptId, id));
        Assert.isTrue(count == 0, "部门下仍关联了人员，无法删除");

        baseMapper.deleteById(dept);

        return dept;
    }

    /**
     * exists with parent id and name
     *
     * @param parentId parent id
     * @param name     dept name
     * @return whether exists
     */
    private boolean existsByParentIdAndName(Long parentId, String name) {
        return baseMapper.selectCount(Wrappers.<Dept>lambdaQuery()
                .eq(Dept::getParentId, parentId)
                .eq(Dept::getName, name)) > 0;
    }
}
